package com.example.demokotlin

import org.junit.Test


/**
 * 泛型测试
 *
 * @author zhouronghua
 * @time 2021/9/17 8:51 上午
 */
class GenericityTest {

    /**
     * 魔术盒子
     *
     * @author zhouronghua
     * @time 2021/9/20 4:29 下午
     */
    class MagicBox<T : Human>(item: T) {
        /**
         * 成员subject存储输入的对象
         */
        private var subject: T = item

        /**
         * 是否可用
         */
        var available = false

        /**
         * 获取对象
         * available为true是返回对象，否则返回null
         *
         * @author zhouronghua
         * @time 2021/9/20 4:09 下午
         */
        fun fetch(): T? {
            return subject.takeIf { available }
        }

        /**
         * 魔术变换
         * 说明: 函数subjectModFunction将T变成R，如果available为true
         *
         * @author zhouronghua
         * @time 2021/9/20 4:18 下午
         */
        fun <R> magicFetch(subjectModFunction: (T) -> R): R? {
            return subjectModFunction(subject).takeIf { available }
        }

        /**
         * 如果产生对象是T类型则直接返回否则使用backup生产T对象
         *
         * @author zhouronghua
         * @time 2021/9/20 5:51 下午
         */
        inline fun <reified T> randomOrBackup(backup: () -> T): T {
            val items = listOf(
                Boy("Lily", 20),
                Man("Milly", 35)
            )
            val random = items.shuffled().first()
            return if (random is T) {
                random
            } else {
                backup()
            }
        }
    }

    /**
     * 魔术盒子列表
     *
     * @author zhouronghua
     * @time 2021/9/20 4:29 下午
     */
    class MagicBoxList<T : Human>(vararg item: T) {
        /**
         * 成员subject存储输入的对象(协边 子类型列表可赋值给父类型列表使用)
         */
        val subjects: Array<out T> = item

        /**
         * 是否可用
         */
        var available = false

        /**
         * 获取对象
         * available为true是返回对象，否则返回null
         *
         * @author zhouronghua
         * @time 2021/9/20 4:09 下午
         */
        fun fetch(index: Int): T? {
            return subjects[index].takeIf { available }
        }

        /**
         * 魔术变换
         * 说明: 函数subjectModFunction将T变成R，如果available为true
         *
         * @author zhouronghua
         * @time 2021/9/20 4:18 下午
         */
        fun <R> magicFetch(index: Int, subjectModFunction: (T) -> R): R? {
            return subjectModFunction(subjects[index]).takeIf { available }
        }

        /**
         * 运算符重载
         * 通过索引获取参数
         *
         * @author zhouronghua
         * @time 2021/9/20 4:55 下午
         */
        operator fun get(index: Int): T? = subjects[index]?.takeIf { available }

        /**
         * 获取参数个数
         *
         * @author zhouronghua
         * @time 2021/9/20 4:56 下午
         */
        fun getSize(): Int {
            return subjects.size
        }
    }

    /**
     * 人类
     */
    open class Human(var name: String, var age: Int)

    /**
     * 男孩
     */
    open class Boy(name: String, age: Int) : Human(name, age)

    /**
     * 男人
     */
    open class Man(name: String, age: Int) : Human(name, age)

    /**
     * 小狗
     */
    class Dog(val weight: Int)

    /**
     * 测试泛型类
     *
     * @author zhouronghua
     * @time 2021/9/20 4:10 下午
     */
    @Test
    fun testGenericity() {
        println("=== 测试泛型类访问 ===")
        val p = MagicBox<Boy>(Boy("李晓明", 20))
        // 设置支持变化ß
        p.available = true
        p.fetch()?.run {
            println("找到了对象Boy 姓名：${this.name}，年龄：${this.age} ")
        }
        // 测试魔术转换
        val man = p.magicFetch {
            Man(it.name, it.age + 20)
        }
        println("Magic Man 姓名: ${man?.name} 年龄：${man?.age}")
    }

    /**
     * 测试魔术盒子列表
     *
     * @author zhouronghua
     * @time 2021/9/20 4:33 下午
     */
    @Test
    fun testMagicBoxList() {
        println("=== 测试泛型类列表参数访问 ===")
        val boxList = MagicBoxList(
            Boy("李晓明", 20),
            Boy("Jacka", 13),
            Boy("丽丽", 25)
        )
        boxList.available = true
        (0 until boxList.getSize()).map {
            // 逐个处理列表参数
            var index = it
            val man = boxList.magicFetch(index) {
                Man(it.name, it.age.plus(20))
            }
            println("magicFetch index: ${index} Magic Man 姓名: ${man?.name} 年龄：${man?.age}")
            // 获取第一个元素
            boxList.fetch(index)?.run {
                println("fetch找到了对象Boy 姓名：${this.name}，年龄：${this.age} ")
            }
        }
    }

    /**
     * 协变（生产者）
     *
     * @author zhouronghua
     * @time 2021/9/20 5:05 下午
     */
    interface Production<out T> {
        fun product(): T
    }

    /**
     * 逆变（消费者）
     *
     * @author zhouronghua
     * @time 2021/9/20 5:05 下午
     */
    interface Consumer<in T> {
        fun consume(item: T)
    }

    /**
     * 不变
     * 泛型类既可以做out，又可以作为in
     *
     * @author zhouronghua
     * @time 2021/9/20 5:03 下午
     */
    interface ProductionConsumer<T> {
        fun product(): T
        fun consume(item: T)
    }

    open class Food

    open class FastFood : Food()

    open class Burger : FastFood()

    class FoodStore : Production<Food> {
        override fun product(): Food {
            println("produce Food...")
            return Food()
        }
    }

    /**
     * 快餐生产工厂
     *
     * @author zhouronghua
     * @time 2021/9/20 5:10 下午
     */
    class FastFoodStore : Production<FastFood> {
        override fun product(): FastFood {
            println("produce FastFood...")
            return FastFood()
        }
    }

    /**
     * 面包生产工厂
     *
     * @author zhouronghua
     * @time 2021/9/20 5:10 下午
     */
    class BurgerStore : Production<Burger> {
        override fun product(): Burger {
            println("produce Burger...")
            return Burger()
        }
    }

    /**
     * 每个人吃食物
     *
     * @author zhouronghua
     * @time 2021/9/20 5:20 下午
     */
    class EveryBody : Consumer<Food> {
        override fun consume(item: Food) {
            println("EveryBody eat food")
        }
    }

    /**
     * 中国人吃快餐
     *
     * @author zhouronghua
     * @time 2021/9/20 5:20 下午
     */
    class Chinese : Consumer<FastFood> {
        override fun consume(item: FastFood) {
            println("Chinese eat FastFood")
        }
    }

    /**
     * 美国人吃面包
     *
     * @author zhouronghua
     * @time 2021/9/20 5:20 下午
     */
    class American : Consumer<Burger> {
        override fun consume(item: Burger) {
            println("American eat Burger")
        }
    }

    /**
     * 协变
     * out(协变)：如果泛型类只将泛型类型作为函数的返回（输出），那么使用out
     * 可以称之为生产类/接口，用来生产指定泛型对象
     * 子类泛型的对象赋值给父类泛型对象
     * in(逆变)
     * 父类泛型对象可以赋值给子类泛型对象
     *
     * @author zhouronghua
     * @time 2021/9/20 4:57 下午
     */
    @Test
    fun testOutIn() {
        println("=== 测试泛型协变和逆变 ===")
        // 指向FastFoodStore
        val production: Production<Food> = FoodStore()
        // 调用的是FastFoodStore.product
        production.product()
        val production2: Production<FastFood> = FastFoodStore()
        production2.product()
        val production3: Production<Burger> = BurgerStore()
        production3.product()
        // in父类传递给子类泛型
        val consumer1: Consumer<Burger> = EveryBody()
        // 调用的是EveryBody.consume
        consumer1.consume(Burger())
        // in父类传递给子类泛型
        val consumer2: Consumer<Burger> = Chinese()
        // 调用的是Chinese.consume
        consumer2.consume(Burger())
        // in父类传递给子类泛型
        val consumer3: Consumer<Burger> = American()
        // 调用的是American.consume
        consumer3.consume(Burger())
    }

    /**
     * 泛型不允许对传入对象做类型检查
     *
     * @author zhouronghua
     * @time 2021/9/20 5:49 下午
     */
    @Test
    fun testReiField() {
        // 想知道泛型参数是什么类型
        val box = MagicBox(Man("小熊爸爸", 45))
        val man = box.randomOrBackup {
            Man("小头爸爸", 40)
        }
        println("获取的值 ${man.name} ${man.age}")
    }
}

